package com.tn.rtdata;

import java.util.Collections;
import java.util.List;

import com.tn.openrpc.RemoteMethod;
import com.tn.openrpc.RemoteMethodException;

/**
 * An implementation of <code>DataSource</code> that uses JMS to receive <code>FillEvent</code>s.
 */
public abstract class EventDrivenDataSource<T> extends DataSource<T>
{
  private static final long DEFAULT_TIMEOUT = 10 * 1000;

  private String fillName;
  private List<?> fillParameters;
  private String fillEventDestination;
  private RemoteMethod fillStartMethod;
  private RemoteMethod fillStopMethod;
  private boolean running;
  private long timeout;
  private Session session;

  /**
   * Creates a new <code>JmsDataSource</code>.
   *
   * @param session                    the associated session.
   * @param fillName                   the name of the fill.
   * @param fillParameters             the parameters of the fill.
   * @param fillStartMethod            the <code>RemoteMethod</code> that starts the fill.
   * @param fillStopMethod             the <code>RemoteMethod</code> that stops the fill.
   * @param dataEventStatsUpdateMethod the <code>RemoteMethod</code> that called to update the data-event stats.
   */
  public EventDrivenDataSource(
    Session session,
    String fillName,
    List<?> fillParameters,
    RemoteMethod fillStartMethod,
    RemoteMethod fillStopMethod,
    RemoteMethod dataEventStatsUpdateMethod,
    String fillEventDestination
  )
  {
    super(dataEventStatsUpdateMethod);
    this.session = session;
    this.fillName = fillName;
    this.fillStartMethod = fillStartMethod;
    this.fillStopMethod = fillStopMethod;
    this.fillParameters = fillParameters;
    this.fillEventDestination = fillEventDestination;
    this.timeout = DEFAULT_TIMEOUT;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected void finalize() throws Throwable
  {
    stop();
    super.finalize();
  }

  /**
   * Returns the fill name.
   */
  public String getFillName()
  {
    return fillName;
  }

  /**
   * Returns the fill parameters.
   */
  public List<?> getFillParameters()
  {
    return Collections.unmodifiableList(fillParameters);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isRunning()
  {
    return running;
  }

  /**
   * Returns the timeout, in milliseconds, allowed for the method call to return.
   */
  public long getTimeout()
  {
    return timeout;
  }

  /**
   * Sets the timeout, in milliseconds, allowed for the method call to return.
   */
  public void setTimeout(long timeout)
  {
    this.timeout = timeout;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void start() throws FillException
  {
    try
    {
      if (!isRunning())
      {
        running = true;
        startFillEventMonitor();

        fillStartMethod.invoke(session.getId(), fillName, fillParameters, fillEventDestination);
      }
    }
    catch (RemoteMethodException e)
    {
      throw new FillException(e);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void stop() throws FillException
  {
    try
    {
      fillStopMethod.invoke(session.getId(), fillName, fillParameters);

      stopFillEventMonitor();
      running = false;
    }
    catch (RemoteMethodException e)
    {
      throw new FillException(e);
    }
  }

  /**
   * Returns the fill-event destination.
   */
  protected String getFillEventDestination()
  {
    return fillEventDestination;
  }

  /**
   * Starts the fill event monitor thread.
   */
  protected abstract void startFillEventMonitor() throws FillException;

  /**
   * Stops the fill event monitor thread.
   */
  protected void stopFillEventMonitor() throws FillException
  {
    //Intentionally blank.
  }
}